<template>
  <div>
    <el-breadcrumb separator-class = "el-icon-arrow-right">
      <el-breadcrumb-item>商品管理</el-breadcrumb-item>
      <el-breadcrumb-item :to = "{path:'/home/goods'}">商品列表</el-breadcrumb-item>
      <el-breadcrumb-item>添加商品</el-breadcrumb-item>
    </el-breadcrumb>
    <!--
    在这里又遇到了一个问题， 那就el-main以及document都出现了滚动栏，所以就有两个滚动栏了，这样看上去让我很不舒服
    首先要明白滚动栏出现的原理，当内容高度大于了容器规定的高度，也就是容器不能一次性展示所有的内容时就会出现滚动条（有些容器需要
    设置overflow:scroll; 才可以） 这里出现了两个滚动条说明有两个内容的高度大于了容器的高度，可以发现一个滚动条在el-main中
    所以el-main中的内容高于了el-main的高度，如果要去除这个滚动条，就要让内容高度小于el-main的高度，或者让el-main的高度大于内容高度
    1. 对el-main使用overflow:hidden;但是会让内容显示不全 不好
    2. 因为el-main都是被内容撑开的，内容高度为100%，所以将el-main的高度设置为110%，但是这样还需要将el-side的高度也设置为110%
    3. 将内容的最大高度设置为固定值，并且overflow-y:scroll; 这样document的滚动条也消失了 但是el-card会出现滚动条
       这个方法挺不错，但是el-card的最大高度为固定值。推荐使用   面包屑不会被遮盖，而且顶栏一直显示
    如果要消除document的滚动条就要让el-main的内容小于能够显示的高度，但是能够显示的高度不能调整，所以能够显示的高度不能大于el-main的高度
    1.因为el-main的高度等于父组件el-container的高度，所以将父组件的高度设置为80%，因为整体的结构为
    el-container-> {el-header,el-container->{el-aside,el-main}} 由于一开始的el-container是一个flex容器
    而且是flex-direction:column; 的flex容器，而且指定el-header的高度为60px，我们只需要将子el-container的高度
    为剩下的像素值就够了，就可以让父el-container占据整个页面，就不再出现滚动条。因为flex会自动分配，所以当给子组件的高度
    小于92%时，flex就会给子el-container分配所有剩下的像素，就算高度为5%也是。所以就不会出现document滚动条
    推荐使用这样的情况  但是这个会让面包屑在滚动的过程中被遮盖，不是很好
    -->
    <el-card class = "box-card">
      <el-alert
          title = "添加商品信息"
          center
          show-icon
          type = "info">
      </el-alert>
      <el-steps :active = "Number(activeStep)" finish-status = "success" simple>
        <el-step v-for = "(item,index) in stepTitle"
                 :key = "index"
                 style = "cursor: pointer"
                 @click.native = "handleStepClick(index)"
                 :title = "item"></el-step>
      </el-steps>
      <!--
      这里将steps的active与tabs的v-model绑定为同一个值，
      注意 steps需要的值是一个数值类型的   tabs需要的值是一个字符串类型的 所以需要进行一下类型转换
      而且最重要的是steps和tabs需要放到同一个div中 不然会报错
      tab-click是tabs的事件，点击标签页时触发，传入参数是当前点击的标签页
      before-leave是tab 的属性，可以传入一个函数作为参数，这个函数接收两个参数，一个是跳转之前的标签一个是跳转之后的标签
      这是切换标签之前的钩子，可以通过传入的函数来判断是否切换标签页
      切换标签之前的钩子，若返回 false 或者返回 Promise 且被 reject，则阻止切换。

      注意这里的写法 将form作为容器 标签页作为内容放在form中的  这样整个标签页中的内容就是一个大的表单，囊括了所有的内容
      非常巧妙
      -->
      <el-form
          label-position = "top"
          :rules = "addGoodsFormRules"
          ref = "addGoodsFormRef"
          :model = "addGoodsForm"
          label-width = "80px">
        <el-tabs
            @tab-click = "handleTabClick"
            :before-leave = "handleBeforeLeave"
            v-model = "activeStep"
            style = "min-height: 280px;"
            tab-position = "left">
          <el-tab-pane name = "0" label = "基本信息">
            <el-form-item prop = "goods_name" label = "商品名称">
              <el-input v-model = "addGoodsForm.goods_name"></el-input>
            </el-form-item>
            <el-form-item prop = "goods_price" label = "商品价格">
              <el-input type = "number" v-model = "addGoodsForm.goods_price"></el-input>
            </el-form-item>
            <el-form-item prop = "goods_weight" label = "商品重量">
              <el-input v-model = "addGoodsForm.goods_weight"></el-input>
            </el-form-item>
            <el-form-item prop = "goods_number" label = "商品数量">
              <el-input v-model = "addGoodsForm.goods_number"></el-input>
            </el-form-item>
            <el-form-item label = "商品分类" prop = "goods_cat">
              <el-cascader
                  :options = "categoriesList"
                  v-model = "addGoodsForm.goods_cat"
                  :props = "{expandTrigger:'hover',label:'cat_name',value:'cat_id'}"
                  @change = "handleCascaderChange">
              </el-cascader>
            </el-form-item>
          </el-tab-pane>
          <el-tab-pane name = "1" label = "商品参数">
            <el-form-item :label = "item.attr_name" v-for = "item in cateManyList" :key = "item.attr_id">
              <el-checkbox-group v-model = "item.attr_vals">
                <el-checkbox border
                             :key = "i"
                             v-for = "(value,i) in item.attr_vals"
                             :label = "value">
                </el-checkbox>
              </el-checkbox-group>
            </el-form-item>
          </el-tab-pane>
          <el-tab-pane name = "2" label = "商品属性">
            <el-form-item :label = "item.attr_name" v-for = "item in cateOnlyList" :key = "item.attr_id">
              <el-input v-model = "item.attr_vals.join(',')"></el-input>
            </el-form-item>
          </el-tab-pane>
          <el-tab-pane name = "3" label = "商品图片">
            <!--
            这里是element的上传模块el-upload，action必选参数，上传的路径 headers 上传的请求头部
            multiple 是否支持多选文件  data上传时的附带参数  name上传文件的字段名 with-credentials支持发送cookie凭证信息
            show-file-list是否显示已上传文件列表 drag是否拖拽上传  accept接受上传的文件类型
            on-preview点击文件列表中已上传的文件时的钩子，preview预览的意思
            on-remove文件列表移除文件的钩子 on-success文件上传成功的钩子 on-error文件上传失败的钩子
            on-progress文件上传的钩子  on-change文件状态改变时的钩子，添加文件、上传成功和上传失败时都会被调用
            before-upload	上传文件之前的钩子，参数为上传的文件，若返回 false 或者返回 Promise 且被 reject，则停止上传。
            before-remove	删除文件之前的钩子，参数为上传的文件和文件列表，若返回 false 或者返回 Promise 且被 reject，则停止删除。
            list-type	文件列表的类型  auto-upload	是否在选取文件后立即进行上传，默认为true
            file-list	上传的文件列表, 例如: [{name: 'food.jpg', url: 'https://xxx.cdn.com/xxx.jpg'}]
            http-request	覆盖默认的上传行为，可以自定义上传的实现
            disabled	是否禁用 limit	最大允许上传个数  on-exceed	文件超出个数限制时的钩子

            这里如果直接使用会上传失败，而且根据响应信息可以知道是无效的token，但是我们明明在axios的请求拦截中配置了token
            所以可以得出这个上传文件并没有使用axios上传，而是使用了组件内部自定义的ajax上传，我们可以在行内中使用
            header属性添加请求头部,该属性接收一个对象   或者使用http-request来覆盖默认的上传行为
            会传入一个参数是上传组件的用于上传的数据   自定义的上传文件失败总是报错不知道为什么
            使用默认的上传，总是成功的，但是可以通过响应参数来判断是否成功
          -->
            <el-upload
                class = "upload-demo"
                :limit = "3"
                action = "http://localhost:8888/api/private/v1/upload"
                :on-remove = "onRemove"
                :headers = "requestHeader"
                :on-exceed = "onExceed"
                :on-preview = "onPreview"
                :on-success = "onSuccess"
                list-type = "picture">
              <el-button size = "small" type = "primary">点击上传</el-button>
              <div slot = "tip" class = "el-upload__tip">只能上传一个文件</div>
            </el-upload>
          </el-tab-pane>
          <el-tab-pane name = "4" label = "商品内容">
            <!--
            这一段的所需要的组件在element中没有需要安装运行依赖vue-quill-editor 富文本编辑器
             -->
            <!-- bidirectional data binding（双向数据绑定） -->
            <quill-editor v-model = "addGoodsForm.goods_introduce"
                          ref = "myQuillEditor">
            </quill-editor>
            <el-button type = "primary" class = "add_goods" @click = "add">添加商品</el-button>
          </el-tab-pane>
        </el-tabs>
      </el-form>
    </el-card>
    <!-- 这个对话框就是显示图片的对话框 -->
    <el-dialog
        :visible.sync = "imgDialogVisible">
      <img :src = "imgDialogUrl" width = "100%">
    </el-dialog>
  </div>
</template>

<script>
import _ from 'lodash'

export default {
  name: 'AddGoods',
  created () { this.getCategoriesList() },
  components: {},
  data () {
    return {
      activeStep: '0',
      stepTitle: [
        '基本信息',
        '商品参数',
        '商品属性',
        '商品图片',
        '商品内容',
        '完成'
      ],
      addGoodsForm: {
        goods_name: '',
        goods_price: '',
        goods_number: '',
        goods_weight: '',
        goods_cat: [52, 1484, 1485],
        pics: [],
        goods_introduce: '',
        attrs: []
      },
      addGoodsFormRules: {
        goods_name: [
          { required: true, message: '商品名称不能为空', trigger: 'blur' },
          { min: 2, message: '长度必须大于2', trigger: 'blur' }
        ],
        goods_price: [{ required: true, message: '价格不能为空', trigger: 'blur' }],
        goods_number: [{ required: true, message: '数量不能为空', trigger: 'blur' }],
        goods_weight: [{ required: true, message: '重量不能为空', trigger: 'blur' }],
        goods_cat: [{ required: true, message: '请选择商品分类,只能选择三级分类', trigger: 'blur' }]

      },
      categoriesList: [],
      cateManyList: [],
      cateOnlyList: [],
      catSel: '',
      requestHeader: {
        Authorization: window.sessionStorage.token
      },
      imgDialogVisible: false,
      imgDialogUrl: ''
    }
  },
  methods: {
    handleStepClick (i) {
      this.activeStep = i + ''
    },
    async handleTabClick (tab) {
      if (this.addGoodsForm.goods_cat.length !== 3) return false
      if (tab.index === '1' || tab.index === '2') {
        tab.index === '1' ? this.catSel = 'many' : this.catSel = 'only'
        const { data: res } = await this.$http.get(`categories/${this.cateId}/attributes`,
          { params: { sel: this.catSel } })
        if (this.process(res)) {
          res.data.forEach(item => {
            item.attr_vals = item.attr_vals.length === 0 ? [] : item.attr_vals.split(',')
          })
          this.catSel === 'many' ? this.cateManyList = res.data : this.cateOnlyList = res.data
        }
      }
    },
    process (res) {
      const status = res.meta.status
      const msg = res.meta.msg
      if (status === 200 || status === 201 || status === 204) {
        this.$message.success(msg)
        return 1
      } else {
        this.$message.error(msg)
        return 0
      }
    },
    async getCategoriesList () {
      const { data: res } = await this.$http.get('categories')
      if (this.process(res)) {
        this.categoriesList = res.data
      }
    },
    handleCascaderChange (val) {
      console.log(this.addGoodsForm.goods_cat)
      // 如果不是三级分类，就让goods_cat为空数组，并且进行表单验证，这样就会出现表单的规则的错误
      if (this.addGoodsForm.goods_cat.length !== 3) {
        this.addGoodsForm.goods_cat = []
        this.$refs.addGoodsFormRef.validateField('goods_cat')
        // 这里是三级分类还是进行一下表单的验证，就可以去除表单错误的提示 validateField也是form的一个方法
        // 可以对单个选项进行表单验证
      } else this.$refs.addGoodsFormRef.validateField('goods_cat')
    },
    handleBeforeLeave (activeName, oldActiveName) {
      // tabs绑定的name是一个字符串需要进行转换为数字 或者与字符串0进行比较
      // console.log('新的:', activeName, '/n  old:', typeof oldActiveName)
      if (oldActiveName === '0' && this.addGoodsForm.goods_cat.length !== 3) {
        this.$message.error('请先选择三级分类')
        this.$refs.addGoodsFormRef.validateField('goods_cat')
        return false
      }
    },
    onExceed () {
      this.$message.error('上传超出限制，请删除已有上传后重试。')
    },
    // 文件上传成功的钩子函数， 传入三个参数，第一个是文件上传成功的响应参数， 第二个是上传的文件 第三个是上传的文件列表
    onSuccess (res, file) {
      if (this.process(res)) {
        this.addGoodsForm.pics.push({ pic: res.data.tmp_path })
      }
    },
    onRemove (file) {
      console.log(file)
      // es6新增语法findIndex，可以使用findIndex来代替下面代码
      // let i
      // this.addGoodsForm.pics.forEach((item, index) => {
      //   if (item.pic === file.response.data.tmp_path) i = index
      // })
      // this.addGoodsForm.pics.splice(i, 1)

      const i = this.addGoodsForm.pics.findIndex(item => {
        return item.pic === file.response.data.tmp_path
      })
      this.addGoodsForm.pics.splice(i, 1)
    },
    // 点击图片列表时触发的钩子函数  让显示图片的对话框显示，然后将图片的src更改为被点击图片的url
    onPreview (file) {
      console.log(file)
      this.imgDialogVisible = true
      this.imgDialogUrl = file.url
    },
    add () {
      // 下面全部是按照后端api的规则来处理数据的
      this.$refs.addGoodsFormRef.validate(async valid => {
        if (!valid) this.$message.error('请按照规则填写')
        // 处理动态参数
        this.cateManyList.forEach(item => {
          const newInfo = {
            attr_id: item.attr_id,
            attr_value: item.attr_vals.join(',')
          }
          this.addGoodsForm.attrs.push(newInfo)
        })
        // 处理静态属性
        this.cateOnlyList.forEach(item => {
          const newInfo = {
            attr_id: item.attr_id,
            attr_value: item.attr_vals.join(',')
          }
          this.addGoodsForm.attrs.push(newInfo)
        })
        // 在发送数据时需要将this.addGoodsForm.goods_cat修改为字符串类型， 但是这样会导致级联选择器报错，因为
        // 级联选择器双向绑定数据为数组类型， 所以我们需要将this.addGoodsForm.goods_cat进行一次深拷贝
        // 在提交时可以将深拷贝的this.addGoodsForm.goods_cat转换为字符串  我们需要使用lodash.js
        // _ 就是引入的lodash 类似于jquery的$ cloneDeep()就是深克隆  使用form接收深克隆后的对象 然后对对象中的数据处理
        const form = _.cloneDeep(this.addGoodsForm)
        form.goods_cat = form.goods_cat.join(',')
        console.log(form)
        const { data: res } = await this.$http.post('goods', form)
        if (this.process(res)) this.$router.push('/home/goods')
      })
    }
  },
  computed: {
    cateId () {
      return this.addGoodsForm.goods_cat[2]
    }
  }
}
</script>

<style scoped>
  .el-card {
    margin-top: 20px;
  }

  .el-steps {
    margin: 20px 0;
  }

  .box-card {
    max-height: 610px;
    overflow-y: scroll;
  }

  .el-checkbox {
    margin: 10px;
  }

  .add_goods {
    margin-top: 20px;
  }
</style>
